package com.tuzhi.convert.mq;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.rabbitmq.client.Channel;
import com.tuzhi.common.domain.ResultBO;
import com.tuzhi.convert.dto.ProcessBoardRespiteDto;
import com.tuzhi.convert.httpclient.ProcessApi;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.messaging.handler.annotation.Headers;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.annotation.Resource;
import java.io.File;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;


@Service
@Slf4j
public class ModelerMqListener {

    @Resource
    ProcessApi processApi;
    @Value("${convert.filepath.cadFiles}")
    private String cadFilePath;
    @Value("${convert.filepath.stepFiles}")
    private String stpFilePath;

    @Value("${convert.filepath.unRarZipFiles}")
    private String unRarZipFilePath;

    @Value("${convert.filepath.cacheFilePath}")
    private String cacheFilePath;

    static final ObjectMapper MAPPER = new ObjectMapper();

    // 创建一个线程池
    static final ThreadPoolExecutor threadPool = new ThreadPoolExecutor(
            // 核心线程数
            10,
            // 最大线程数
            15,
            // 线程存活时间
            1000000,
            // 时间单位
            TimeUnit.SECONDS,
            // 任务队列
            new ArrayBlockingQueue(12),
            // 拒绝策略
            new ThreadPoolExecutor.AbortPolicy());

    /**
     * 这样设计最优的情形任务是按：4+4+2过来的，
     * 如果过来的消息队列阶段批量是大理同一类型的任务则会出现不优的情况
     * 可以考虑设置分别的消息队列---这样设计好像也有问题
     */
//    static final ArrayBlockingQueue<Integer> queue_prt = new ArrayBlockingQueue<>(4);
//    static final ArrayBlockingQueue<Integer> queue_x_t = new ArrayBlockingQueue<>(4);
//    static final ArrayBlockingQueue<Integer> queue_other = new ArrayBlockingQueue<>(2);
    static final ArrayBlockingQueue<Integer> queue_all = new ArrayBlockingQueue<>(8);

    @RabbitListener(containerFactory = "consListenerContainer_convert", queues = "${convertMq.queueName}", ackMode = "AUTO")
    public void receiveMsg(Message msg, @Headers Map<String, Object> headers, Channel channel) {
        String orderNo = null;
        try {
            String msgContent = new String(msg.getBody());
            log.info("消息队列接收消息modelId：{}", msgContent);
            orderNo = msgContent;
            //1.获取暂缓板件文件信息
            ResultBO<List<ProcessBoardRespiteDto>> resultModelInfo = processApi.getProcessBoardRespite(orderNo);
            log.info(resultModelInfo.toString());
            if (!resultModelInfo.isSuccess() && resultModelInfo.getData() == null) {
                log.info("获取暂缓板件文件信息失败。modelId={}", orderNo);
                return;
            }
            List<ProcessBoardRespiteDto> processBoardRespiteDtos = resultModelInfo.getData();

            processBoardRespiteDtos.forEach(processBoardRespiteDto -> {
                ArrayBlockingQueue<Integer> queue = null;
                queue = queue_all;
                try {
                    queue.take();
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
                Callback callback = buildCallback(queue);
                MakeModelerTask makeModelerTask = new MakeModelerTask(processBoardRespiteDto , cadFilePath, stpFilePath, unRarZipFilePath,
                        cacheFilePath , callback);
                log.info("提交任务到线程池。。。。");
                threadPool.submit(makeModelerTask);
            });
        } catch (Exception exception) {
            log.error("转换器消息队列转换程序出错,orderNo:" + orderNo, exception);
            Map dataMap = new HashMap();
            Map statMap = new HashMap();
            dataMap.put("data", statMap);
            statMap.put("status", "error");
            //processApi.setStatus(dataMap, orderNo);
        }
    }


    public Callback buildCallback(ArrayBlockingQueue<Integer> queue) {
        return obj -> {
            /*try {
                queue.take();
                log.info("modelId={},交还任务令牌。", obj);
            } catch (InterruptedException e) {
                log.error("modelId=" + obj + "，任务结束回调方法失败。", e);
                throw new RuntimeException(e);
            }*/
            queue.offer(1);
            log.info("modelId={},交还任务令牌。", obj);
        };
    }

    @PostConstruct
    public void initialize() {
       /* queue_prt.offer(1);
        queue_prt.offer(1);
        queue_prt.offer(1);
        queue_prt.offer(1);
        queue_x_t.offer(1);
        queue_x_t.offer(1);
        queue_x_t.offer(1);
        queue_x_t.offer(1);
        queue_x_t.offer(1);
        queue_other.offer(1);*/
        queue_all.offer(1);
        queue_all.offer(1);
        queue_all.offer(1);
        queue_all.offer(1);
        queue_all.offer(1);
        queue_all.offer(1);
        queue_all.offer(1);
        queue_all.offer(1);
        File unZip = new File(unRarZipFilePath);
        if (!unZip.exists()) {
            unZip.mkdirs();
        }
        File stpFile = new File(stpFilePath);
        if (!stpFile.exists()) {
            stpFile.mkdirs();
        }
    }

    @PreDestroy
    public void destroy() throws Exception {
        log.info("关闭线程池。。。。");
        threadPool.shutdown();
        if (!threadPool.awaitTermination(36, TimeUnit.SECONDS)) {//20S
            log.warn(" 到达指定时间，还有线程没执行完，不再等待，关闭线程池!");
            threadPool.shutdownNow();
        }
    }

    public static void main(String[] args) throws InterruptedException {
        ArrayBlockingQueue<Integer> queue_prt = new ArrayBlockingQueue<>(4);
        queue_prt.offer(1);
        queue_prt.offer(1);
        queue_prt.offer(1);
        queue_prt.offer(1);
        if (queue_prt.offer(1)) {
            System.out.println("成功添加");
        } else {
            System.out.println("队列已满");
        }
        queue_prt.put(2);
        // 判断队列是否已满
        if (queue_prt.remainingCapacity() == 0) {
            System.out.println("Queue is full.");
        }
        ArrayBlockingQueue queue = new ArrayBlockingQueue(3);
        // 添加三个元素
        queue.offer(1);
        queue.offer(2);
        queue.offer(3);

        // 尝试添加第四个元素
        if (!queue.offer(4)) {
            System.out.println("队列已满！");
        } else {
            System.out.println("元素4已添加到队列中。");
        }
    }

}
